// Package comm 公共函数定义
package comm

import (
	"errors"
	"ginbase/zConfig"
	"io/ioutil"
	"log"
	"math/rand"
	"os"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gomodule/redigo/redis"
	uuid "github.com/satori/go.uuid"
)

// GetParamWithPanic 获取请求参数 如果没有直接抛异常
func GetParamWithPanic(c *gin.Context, key string) string {
    v := GetParam(c, key)
    if "" == v {
        panic("没有参数" + key)
    } else {
        return v
    }
}

// GetParam 获取请求中的参数
func GetParam(c *gin.Context, key string) string {
    if "POST" == c.Request.Method && "" != c.PostForm(key) {
        return c.PostForm(key)
    } else if "GET" == c.Request.Method || ("POST" == c.Request.Method && "" != c.Query(key)) {
        return c.Query(key)
    } else {
        return ""
    }
}

// 获取带默认值的请求参数
func GetParamDefault(c *gin.Context, key, defaultValue string) string {
    if "POST" == c.Request.Method && "" != c.PostForm(key) {
        return c.DefaultPostForm(key, defaultValue)
    } else if "GET" == c.Request.Method || ("POST" == c.Request.Method && "" != c.Query(key)) {
        return c.DefaultQuery(key, defaultValue)
    } else {
        return defaultValue
    }
}

// GetParamExist 获取请求参数并判断请求参数是否存在
func GetParamExist(c *gin.Context, key string) (string, bool) {
    if "GET" == c.Request.Method {
        return c.GetQuery(key)
    } else if "POST" == c.Request.Method {
        return c.GetPostForm(key)
    } else {
        return "", false
    }
}

// Perror 打印出错信息并抛出异常
func Perror(err error, errMsg string) {
    if nil != err {
        log.Println(err)
        panic(errMsg)
    }
}

// ReadFile 读取文件
func ReadFile(filename string) ([]byte, error) {
    return ioutil.ReadFile(filename)
}

// 获取UUID V4 纯随机
func GetUUIDV4() string {
    // 初始化纯随机的UUID
    u1 := uuid.Must(uuid.NewV4())
    return u1.String()
}

// 程序是否运行在docker环境中
func isRunningInDockerContainer() bool {
    // docker creates a .dockerenv file at the root
    // of the directory tree inside the container.
    // if this file exists then the viewer is running
    // from inside a container so return true
    if _, err := os.Stat("/.dockerenv"); err == nil {
        return true
    }
    return false
}

// 连接缓存redis
func ConnCacheRedis(redisConfigs []*zConfig.Redis) (redis.Conn, error) {
    var conn redis.Conn
    var err error
    // 默认连接的redis
    var defautKey string = "default"
    // 如果没有redis连接的配置
    if 0 == len(redisConfigs) {
        log.Println("配置文件中没有redis连接配置")
        return nil, errors.New("没有redis连接配置")
    }
    // 如果在docker环境下
    if isRunningInDockerContainer() {
        // 修改需要连接的默认redis
        defautKey = "defaultDocker"
    }
    log.Printf("连接redis key:%s", defautKey)
    // 连接redis
    conn, err = ConnRedis(redisConfigs, defautKey)
    if nil != err {
        log.Printf("连接redis失败, 错误消息:%v", err)
        return nil, err
    }
    return conn, nil
}

// 连接redis
func ConnRedis(redisConfigs []*zConfig.Redis, key string) (redis.Conn, error) {
    var conn redis.Conn
    var err error
    for _, r := range redisConfigs {
        // 跳过不需要连接的redis
        if key != r.Key {
            continue
        }
        // 不带密码
        if "" == r.Pwd {
            conn, err = redis.Dial("tcp", r.Address)
        } else {
            // 带密码
            conn, err = redis.Dial("tcp", r.Address, redis.DialPassword(r.Pwd))
        }
        if nil != err {
            log.Println(err)
            return conn, err
        }
    }
    return conn, nil
}

// 连接全部redis
func ConnRedises(redisConfigs []*zConfig.Redis) ([]redis.Conn, error) {
    var conns []redis.Conn
    var err error
    for _, r := range redisConfigs {
        var conn redis.Conn
        // 不带密码
        if "" == r.Pwd {
            conn, err = redis.Dial("tcp", r.Address)
        } else {
            // 带密码
            conn, err = redis.Dial("tcp", r.Address, redis.DialPassword(r.Pwd))
        }
        if nil != err {
            log.Println(err)
            return conns, err
        }
        conns = append(conns, conn)
    }
    return conns, nil
}

// 生成singleFlight的key
func GetSingleflightKey(params ...string) string {
    return strings.Join(params, "|")
}

// 生成随机失效时间
func GetRandomExpiredTime() int {
    // 随机数种子
    rand.Seed(time.Now().Unix())
    return 1800 + rand.Intn(1200)
}

// 获取cmd
func GetCMD(c *gin.Context) string {
    // 调用接口的cmd
    var cmd string
    // 先检查url上的参数key=value和body中key：value中的cmd是否存在
    cmd = GetParam(c, "cmd")
    // cmd没有设置值
    if "" == cmd {
        // 检查/api/:cmd中的cmd是否存在
        cmd = c.Param("cmd")
    }
    // cmd还是不存在
    if "" == cmd {
        log.Println("cmd不存在")
    }
    return cmd
}